home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / comirq.zip / COMIRQ.C next >
C/C++ Source or Header  |  1992-12-20  |  5KB  |  244 lines

  1. #if 0
  2.  
  3. A little program to find all the COM ports on a PC - including ones not
  4. known to the BIOS and then test what IRQ they are using.
  5.  
  6. If you replace main() with a public function and do something useful instead
  7. of all the printf()'s then it's easily converted into a useful module.
  8.  
  9. I use Borland C++ compiler.
  10.  
  11. Roger Barker, December 1992.
  12. CIS 100023,106.
  13.  
  14. #endif
  15.  
  16. #include <stdio.h>
  17. #include <dos.h>
  18.  
  19. typedef void interrupt (INT_FUNC)(void);
  20. typedef unsigned char UCHAR;
  21.  
  22. typedef struct
  23. {
  24.     int addr;
  25.     int bios;
  26. } COM_INF;
  27.  
  28. #define    dim(x)    (sizeof((x))/sizeof((x)[0]))
  29.  
  30. #define    TRUE        1
  31. #define    FALSE        0
  32.  
  33. #define    IRQ3        3
  34. #define    IRQ4        4
  35. #define    EOI        0x20
  36. #define    INTA00    0x20
  37. #define    INTA01    0x21
  38.  
  39.  
  40. static void UninstallISR(int irq, INT_FUNC *old_func);
  41. static INT_FUNC *InstallISR(int irq, INT_FUNC *service_func);
  42. static void interrupt ServiceIRQ3(void);
  43. static void interrupt ServiceIRQ4(void);
  44. static void CheckCOMsAvailable(void);
  45. static int CheckFitted(int addr);
  46.  
  47.  
  48. static COM_INF our_coms[4];
  49.  
  50. static INT_FUNC *old_irq3;
  51. static INT_FUNC *old_irq4;
  52. static int trigger_3, trigger_4;
  53.  
  54. void main(void)
  55. {
  56.     int i, com, count = 0;
  57.     UCHAR old_int, old_modem;
  58.     UCHAR old_inta01;
  59.  
  60.     /*
  61.      *    setup a table in our_coms of all COM ports known to the BIOS and
  62.      *    also any more that we can find.
  63.      */
  64.     CheckCOMsAvailable();
  65.  
  66.     /*
  67.      *    setup our ISR's and save the original interrupt state.
  68.      */
  69.     old_inta01 = inportb(INTA01);
  70.     old_irq3 = InstallISR(IRQ3, ServiceIRQ3);
  71.     old_irq4 = InstallISR(IRQ4, ServiceIRQ4);
  72.  
  73.     for (i = 0; i < 4 && our_coms[i].addr; i++)
  74.     {
  75.         com = our_coms[i].addr;
  76.  
  77.         if (our_coms[i].bios)
  78.             printf("COM%d is at %3X. ", ++count, com);
  79.         else
  80.             printf("There is a COM at %3X, the BIOS has not found it. ", com);
  81.  
  82.         /*
  83.          *    save original state of interrupt enable register and
  84.          *    enable TX buffer empty interrupt.
  85.          */
  86.         old_int = inportb(com+1);
  87.         outportb(com+1, 2);
  88.  
  89.         /*
  90.          *    save original state of modem control register and
  91.          *    set OUT2 to allow 8250 to generate interrupts.
  92.          */
  93.         old_modem = inportb(com+4);
  94.         outportb(com+4, 8);    /* global interrupt enable */
  95.  
  96.         /*
  97.          *    clear flags and send a nul. TX buffer interrupt will be generated
  98.          *    when it has gone.
  99.          */
  100.         trigger_3 = trigger_4 = FALSE;
  101.         outportb(com,0);
  102.         /*
  103.          *    a little wait. This could fail if the divisor latch is set to
  104.          *    a totally silly value - may be worth setting it?
  105.          */
  106.         delay(500);
  107.  
  108.         /*
  109.          *    put things back as they were.
  110.          */
  111.         outportb(com+1, old_int);
  112.         outportb(com+4, old_modem);
  113.  
  114.         /*
  115.          *    check which IRQ has been triggered. NB this code allows for the
  116.          *    impossible? situation of both IRQ's being triggered.
  117.          */
  118.         if (trigger_3)
  119.             printf("It is using IRQ3. \n");
  120.         if (trigger_4)
  121.             printf("It is using IRQ4.\n");
  122.         if (!trigger_3 && !trigger_4)
  123.             printf("It is not using IRQ3 or IRQ4\n");
  124.     }
  125.  
  126.     /*
  127.      *    restore the original state of IRQ3, IRQ4 and the 8259 mask.
  128.      */
  129.     UninstallISR(IRQ3, old_irq3);
  130.     UninstallISR(IRQ4, old_irq4);
  131.     outportb(INTA01, old_inta01);
  132. }
  133.  
  134.  
  135. static INT_FUNC *InstallISR(int irq, INT_FUNC *service_func)
  136. {
  137.     UCHAR mask, inta01_val;
  138.     INT_FUNC *old_func;
  139.  
  140.     mask = ~(1 << irq);
  141.  
  142.     old_func = getvect(irq + 8);
  143.     setvect(irq+8, service_func);
  144.     inta01_val = inportb(INTA01);
  145.     outportb(INTA01, mask & inta01_val);
  146.  
  147.     return old_func;
  148. }
  149.  
  150.  
  151. static void UninstallISR(int irq, INT_FUNC *old_func)
  152. {
  153.     UCHAR mask, inta01_val;
  154.  
  155.     if (!old_func)
  156.         return;
  157.  
  158.     mask = 1 << irq;
  159.  
  160.     setvect(irq+8, old_func);
  161.     inta01_val = inportb(INTA01);
  162.     outportb(INTA01, inta01_val | mask);
  163. }
  164.  
  165.  
  166. static void interrupt ServiceIRQ3(void)
  167. {
  168.     trigger_3 = TRUE;
  169.     outportb(INTA00, EOI);
  170. }
  171.  
  172.  
  173. static void interrupt ServiceIRQ4(void)
  174. {
  175.     trigger_4 = TRUE;
  176.     outportb(INTA00, EOI);
  177. }
  178.  
  179.  
  180. /*
  181.  *    set up in our_coms all the COM ports known to the BIOS and then check
  182.  *    for any other ports fitted that the BIOS hasn't found.
  183.  */
  184. static void CheckCOMsAvailable(void)
  185. {
  186.     int *bioscom = (int *)0x400000;
  187.     int i, j, count = 0;
  188.     int addr_list[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x3e0, 0x2e0};
  189.  
  190.     /*
  191.      *    enter all the COMs known to the BIOS into our_coms.
  192.      */
  193.     for (i = 0; i < 4 && bioscom[i]; i++)
  194.     {
  195.         our_coms[count].addr = bioscom[i];
  196.         our_coms[count++].bios = TRUE;
  197.     }
  198.  
  199.     /*
  200.      *    now run through our address list and see if there are any more
  201.      *    COMs that the BIOS hasn't found.
  202.      */
  203.     for (i = 0; i < dim(addr_list) && count < 4; i++)
  204.     {
  205.         /*
  206.          *    abandon it if it is already in the table.
  207.          */
  208.         for (j = 0; j < count; j++)
  209.             if (our_coms[j].addr == addr_list[i])
  210.                 break;
  211.         if (j != count)
  212.             continue;
  213.  
  214.         if (CheckFitted(addr_list[i]))
  215.         {
  216.             our_coms[count].addr = addr_list[i];
  217.             our_coms[count++].bios = FALSE;
  218.         }
  219.     }
  220. }
  221.  
  222.  
  223. /*
  224.  *    CheckFitted is partly cribbed from the PC-XT ROM BIOS. It attempts to read
  225.  *    the interrupt identification register of the 8250. If the chip is there
  226.  *    then the top 5 bits will be '0'. I have also added a write/read test of
  227.  *    the line control register. There are surely better ways of finding 8250's!
  228.  */
  229. static int CheckFitted(int addr)
  230. {
  231.     UCHAR byte;
  232.     int ret;
  233.  
  234.     if (inportb(addr+2) & 0xf8)
  235.         return FALSE;
  236.  
  237.     byte = inportb(addr+3);    /* save original value */
  238.     outportb(addr+3, 0x3f);
  239.     ret = (inportb(addr+3) == 0x3f);
  240.     outportb(addr+3,byte);    /* restore original value */
  241.  
  242.     return ret;
  243. }
  244.